package beats

import (
	"encoding/json"
	"gluenet/pkg/apis"
	"gluenet/pkg/meta"
	v2 "gluenet/utils/rpc/v2/define"
	"strings"
	"sync"
	"time"
)

func HeartBeatNew(ctx *apis.StorageContext) {
	//ctx.Logger.Debugf("REQ heart beat")

	req := &v2.HeartBeats{}
	if err := json.Unmarshal(ctx.RpcContext.Data.Data, req); err != nil {
		ctx.Logger.Errorf("unmarshall heart beat request failed")
		return
	}

	for guid, beat := range req.Beats {
		var platform, hostname string
		if beat.Platform == "" || beat.HostName == "" {
			var ags *meta.Agent

			if err := ctx.DataBase.AgentGet(guid, &ags); err != nil {
				continue
			}

			hostname = ags.Hostname
			if tags, err := meta.DeCodeTags(ags.Tags); err != nil {
				continue
			} else if tag, ok := tags["platform"]; ok {
				platform = tag
			}

			//fmt.Printf("host %v plat %v", hostname, platform)
			updateInfo(ctx, guid, platform, hostname, meta.StateReady)
		} else {
			updateInfo(ctx, guid, beat.Platform, beat.HostName, meta.StateReady)
		}
	}
}

func updateInfo(c *apis.StorageContext, guid, platform, nodeName, state string) {
	var key = strings.Join([]string{platform, "agent_state", guid, nodeName}, "|")

	data := map[string]interface{}{
		"object":   "machine",
		"platform": platform,
		"time":     time.Now().Unix(),
		"label":    "agent_state",
		"value":    meta.StateReady,
		"guid":     guid,
		"name":     nodeName,
	}

	var sub *sync.Map
	subi, _ := c.StatusSubscriber.LoadOrStore(key, &sync.Map{})
	sub = subi.(*sync.Map)

	bts, _ := json.Marshal(data)
	str := string(bts)
	sub.Range(func(k, v interface{}) bool {
		mch := v.(chan string)
		mch <- str
		return true
	})

	c.StatusSubscriberTotal.Range(func(k, v interface{}) bool {
		mch := v.(chan string)
		mch <- str
		return true
	})

	key2 := strings.Join([]string{platform, "agent_state", guid}, "|")
	infosi, ok := c.InfoFlusher.Info.LoadOrStore(key2, make(map[string]string))
	infos := infosi.(map[string]string)
	infos[nodeName] = meta.StateReady
	if !ok {
		c.InfoFlusher.Func.Store(key2, func(k, v interface{}) error {
			agentGuid := strings.Split(k.(string), "|")[2]
			detail, i := make([]string, len(v.(map[string]string))), 0
			for p, n := range v.(map[string]string) {
				detail[i] = strings.Join([]string{p, n}, ",")
				i++
			}
			stateStr := strings.Join(detail, "|")
			if err := c.DataBase.AgentRuntimeStatusUpdate(agentGuid, stateStr); err != nil {
				c.Logger.Warnf("update %v runtime container %v", agentGuid, err)
			}
			return nil
		})
	}
}

//func updateStatusImplNew(ctx *apis.GlueContext, guid, state string) error {
//	if _, err := ctx.DataBase.MetaDB().Exec(`UPDATE agent_status SET status=? WHERE guid = ?`, state, guid); err != nil {
//		return err
//	}
//	return nil
//}
